package com.macaline.util;

import net.sf.json.JSONObject;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import java.io.ByteArrayInputStream;
import java.util.*;

/**
 * xml工具类
 */
public class XmlUtil {
	/**
	 * 获取xmlString
	 * @param element xml对象
	 * @return
	 */
	public static String getString(Element element){
		Format format = Format.getPrettyFormat();
		format = format.setOmitDeclaration(true);
		format = format.setOmitEncoding(true);
		XMLOutputter out = new XMLOutputter(format.setEncoding("UTF-8"));
		return out.outputString(element);
	}

	/**
	 * map转xml对象
	 * @param map 需要转换的map
	 * @return
	 */
	public static String mapToXml(Map map){
		return getString(mapToElement(null, map));
	}
	/**
	 * map转xml对象
	 * @param element 根路径
	 * @param map 需要转换的map
	 * @return
	 */
	public static String mapToXml(Element element, Map map){
		return getString(mapToElement(element, map));
	}

	/**
	 * map转xml对象
	 * @param map 需要转换的map
	 * @return
	 */
	public static Element mapToElement(Map map) {
		return mapToElement(null, map);
	}


	/**
	 * map转xml对象
	 * @param root 根，没有可传null
	 * @param map 需要转换的map
	 * @return
	 */
	public static Element mapToElement(Element root, Map map){
		Set set = map.keySet();
		Element item = null;
		for (Object keys : set) {
			String key = (String) keys;
			Object value = map.get(key);
			item = new Element(key);
			if (value instanceof Map) {
				Element element = mapToElement(item, (Map) value);
				if(root != null){
					root.addContent(element);
				}else {
					root = item;
				}
			}
			if(value instanceof String) {
				item.setText((String) value);
				if(root == null){
					root = item;
				}else {
					root.addContent(item);
				}
			}
		}
		return root;
	}

	/**
	 * 将xml字符串传为map
	 * @author warm_joy
	 * @param xmlString 需要转换的xml字符串
	 * @return 返回组装好的JSONObject类
	 */
	public static Map stringToMap(String xmlString) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			//将字符串转为字节并以流的方式创建
			ByteArrayInputStream inputStream = new ByteArrayInputStream(xmlString.getBytes());
			//创建读取xml文件的解析器
			SAXBuilder builder = new SAXBuilder();
			//得到document
			Document doc = builder.build(inputStream);
			//得到根元素
			Element root = doc.getRootElement();
			//得到根元素的所有子元素，即二级标签
			List list = root.getChildren();
			//遍历所有的一级元素
			Iterator iterator = list.iterator();
			while(iterator.hasNext()) {
				//取出每个元素的name 和 value ，封装到map中
				Element e = (Element)iterator.next();
				String k = e.getName();
				Object v = null;
				List children = e.getChildren();
				//判断该标签是否还有子元素
				if(children.isEmpty()) {
					//得到标签中的值
					v = e.getText();
				}else {
					//如果有子节点堆子节点进行处理
					v = stringToMap(getString(e));
				}
				//保存遍历的值
				map.put(k,v);
			}
			//释放流
			inputStream.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return map;
	}

	/**
	 * 获取子节点的xml
	 * @author warm_joy
	 * @param children 子节点的列表
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	private static String getChildrenText(List children) {
		//创建用于拼装结果的类
		StringBuffer sb = new StringBuffer();
		//标签开始循环，加上开始符号
		sb.append("{");
		//进行循环遍历
		if (!children.isEmpty()) {
			//循环遍历子元素
			Iterator it = children.iterator();
			while (it.hasNext()) {
				Element e = (Element) it.next();
				String name = e.getName();
				String value = e.getTextNormalize();
				List list = e.getChildren();
				//判断当前的元素是否还有子元素，然后按照相应的拼装规则进行拼装字符串
				boolean empty = !list.isEmpty();
				if(!empty) {
					sb.append(name + "=\"");
				}else {
					sb.append(name + "=");
				}
				//如果还有下一级的标签，继续循环
				if (empty) {
					sb.append(getChildrenText(list));
				}
				//判断当前的元素是否还有子元素，然后按照相应的拼装规则进行拼装字符串
				if(!empty) {
					sb.append(value + "\"");
				}else {
					sb.append(value);
				}

				//如果此标签不是同等级最后一个标签，添加分隔符号
				if(it.hasNext()) {
					sb.append(",");
				}
			}
		}
		//标签循环结束，加上结束符号
		sb.append("}");

		return sb.toString();
	}

	/**
	 * 转换xml字符串为json
	 * @param xmlString xml字符创
	 * @return
	 */
	public static JSONObject stringToJson(String xmlString) {
		return stringToJson(xmlString);
	}
}
